<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="utf-8">
	<title>Three.js CCDIKSolver Browser</title>
	<!-- <link rel="shortcut icon" href="../../files/favicon.ico" />
	<link rel="stylesheet" type="text/css" href="../../files/main.css"> -->
	<style>
        *{
            margin: 0;
            padding: 0;
        }
		canvas {
			display: block;
			width: 100%;
			height: 100%;
		}

		#newWindow {
			display: block;
			position: absolute;
			bottom: 0.3em;
			left: 0.5em;
			color: #fff;
		}
        .container{
            position: fixed;
            /* height: 300px; */
            width: 200px;
            top:20px;
            z-index: 999;
            background: white;
            
        }
        .container{
            left: 20px;
            width:200px;
            position: fixed;
        }
	</style>
</head>

<body>

	<!-- Import maps polyfill -->
	<!-- Remove this when import maps will be widely supported -->
	<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/electroluxasset/mediapipe/holistic/camera_utils.js" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/electroluxasset/mediapipe/holistic/control_utils.js"
        crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/electroluxasset/mediapipe/holistic/drawing_utils.js"
        crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/electroluxasset/mediapipe/holistic/holistic.js" crossorigin="anonymous"></script>
	<script type="importmap">
			{
				"imports": {
					"three": "https://unpkg.com/three/build/three.module.js",
					"CCDIKSolver.js": "https://unpkg.com/three/examples/jsm/animation/CCDIKSolver.js",
                    "GUI": "https://unpkg.com/three/examples/jsm/libs/lil-gui.module.min.js",
                    "OrbitControls": "https://unpkg.com/three/examples/jsm/controls/OrbitControls.js"
                }
			}
		</script>

        <div class="container">
            <video class="input_video"></video>
           
        </div>
	<script type="module">
		

        
        //
		// Forked from /docs/api/en/objects/SkinnedMesh example
		//

		import {
			Bone,
			Color,
			CylinderGeometry,
			DoubleSide,
			Float32BufferAttribute,
			MeshPhongMaterial,
			PerspectiveCamera,
			Scene,
			SkinnedMesh,
			Skeleton,
			SkeletonHelper,
			Vector3,
			Uint16BufferAttribute,
			WebGLRenderer
		} from 'three';
		import { CCDIKSolver, CCDIKHelper } from 'CCDIKSolver.js';

		import { GUI } from 'GUI';
		import { OrbitControls } from 'OrbitControls';

		let gui, scene, camera, renderer, orbit, mesh, bones, skeletonHelper, ikSolver;

		const state = {
			ikSolverAutoUpdate: true
		};

		function initScene() {

			gui = new GUI();

			scene = new Scene();
			scene.background = new Color(0x444444);

			camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 200);
			camera.position.z = 30;
			camera.position.y = 30;

			renderer = new WebGLRenderer({ antialias: true });
			renderer.setPixelRatio(window.devicePixelRatio);
			renderer.setSize(window.innerWidth, window.innerHeight);
			document.body.appendChild(renderer.domElement);

			orbit = new OrbitControls(camera, renderer.domElement);
			orbit.enableZoom = false;

			window.addEventListener('resize', function () {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize(window.innerWidth, window.innerHeight);

			}, false);

			initBones();
			setupDatGui();

		}

		function createGeometry(sizing) {

			const geometry = new CylinderGeometry(
				5, // radiusTop
				5, // radiusBottom
				sizing.height, // height
				8, // radiusSegments
				sizing.segmentCount * 1, // heightSegments
				true // openEnded
			);

			const position = geometry.attributes.position;

			const vertex = new Vector3();

			const skinIndices = [];
			const skinWeights = [];

			for (let i = 0; i < position.count; i++) {

				vertex.fromBufferAttribute(position, i);

				const y = (vertex.y + sizing.halfHeight);

				const skinIndex = Math.floor(y / sizing.segmentHeight);
				const skinWeight = (y % sizing.segmentHeight) / sizing.segmentHeight;

				skinIndices.push(skinIndex, skinIndex + 1, 0, 0);
				skinWeights.push(1 - skinWeight, skinWeight, 0, 0);

			}

			geometry.setAttribute('skinIndex', new Uint16BufferAttribute(skinIndices, 4));
			geometry.setAttribute('skinWeight', new Float32BufferAttribute(skinWeights, 4));

			return geometry;

		}

		function createBones(sizing) {

			bones = [];

			// "root bone"
			const rootBone = new Bone();
			rootBone.name = 'root';
			rootBone.position.y = - sizing.halfHeight;
			bones.push(rootBone);

			//
			// "bone0", "bone1", "bone2", "bone3"
			//

			// "bone0"
			let prevBone = new Bone();
			prevBone.position.y = 0;
			rootBone.add(prevBone);
			bones.push(prevBone);

			// "bone1", "bone2", "bone3"
			for (let i = 1; i <= sizing.segmentCount; i++) {

				const bone = new Bone();
				bone.position.y = sizing.segmentHeight;
				bones.push(bone);
				bone.name = `bone${i}`;
				prevBone.add(bone);
				prevBone = bone;

			}

			// "target"
			const targetBone = new Bone();
			targetBone.name = 'target';
			targetBone.position.y = sizing.height + sizing.segmentHeight; // relative to parent: rootBone
			rootBone.add(targetBone);
			bones.push(targetBone);

			return bones;

		}

		function createMesh(geometry, bones) {

			const material = new MeshPhongMaterial({
				color: 0x156289,
				emissive: 0x072534,
				side: DoubleSide,
				flatShading: true,
				wireframe: true
			});
			console.log("geometry",geometry)
			// 第一个是 
			const mesh = new SkinnedMesh(geometry, material);
			const skeleton = new Skeleton(bones);

			mesh.add(bones[0]);

			mesh.bind(skeleton);

			skeletonHelper = new SkeletonHelper(mesh);
			skeletonHelper.material.linewidth = 20000;
			scene.add(skeletonHelper);

			return mesh;

		}
        var boneAll
		function setupDatGui() {

			gui.add(mesh, 'pose').name('mesh.pose()');

			mesh.skeleton.bones
				.filter((bone) => bone.name === 'target')
				.forEach(function (bone) {
                    boneAll= bone
				// 	setInterval(()=>{
				// 	bone.position.x = bone.position.x+1
				// },1000)
					const folder = gui.addFolder(bone.name);

					const delta = 20;
					folder.add(bone.position, 'x', - delta + bone.position.x, delta + bone.position.x);
					folder.add(bone.position, 'y', - bone.position.y, bone.position.y);
					folder.add(bone.position, 'z', - delta + bone.position.z, delta + bone.position.z);

				});

			gui.add(ikSolver, 'update').name('ikSolver.update()');
			gui.add(state, 'ikSolverAutoUpdate');

		}

		function initBones() {

			const segmentHeight = 8;
			const segmentCount = 3;
			const height = segmentHeight * segmentCount;
			const halfHeight = height * 0.5;

			const sizing = {
				segmentHeight,
				segmentCount,
				height,
				halfHeight
			};

			const geometry = createGeometry(sizing);
			const bones = createBones(sizing);


			console.log("geo", geometry)
			console.log("bones", bones)
			mesh = createMesh(geometry, bones);

			scene.add(mesh);

			//
			// ikSolver
			//

			const iks = [
				{
					target: 5,
					effector: 4,
					links: [{ index: 3 }, { index: 2 }]
				}
			];

			
			console.log(mesh, "mesh")
			ikSolver = new CCDIKSolver(mesh, iks);
			scene.add(new CCDIKHelper(mesh, iks));

		}

		function render() {

			requestAnimationFrame(render);

			if (state.ikSolverAutoUpdate) {

				ikSolver?.update();

			}

			renderer.render(scene, camera);

		}

		initScene();
		render();

   




        const videoElement = document.getElementsByClassName('input_video')[0];
       
       function onResults(results) {
   
           //输出 33 个点   z 是深度 越近 就越小  以米为单位的真实世界 3D 坐标，
           console.log(results.poseLandmarks)
           
           boneAll.position.x = 30 *(results.poseLandmarks[0].x-0.5)
           boneAll.position.z = 15 *(-1.5-results.poseLandmarks[0].z)
       }

       const holistic = new Holistic({
           locateFile: (file) => {
               console.log(file,"file")
               return `https://cdn.jsdelivr.net/npm/electroluxasset/mediapipe/holistic/locate/${file}`;
           }
       });
       holistic.setOptions({
           modelComplexity: 1,
           smoothLandmarks: true,
           enableSegmentation: true,
           smoothSegmentation: true,
           refineFaceLandmarks: true,
           minDetectionConfidence: 0.5,
           minTrackingConfidence: 0.5
       });
       holistic.onResults(onResults);

       const camera1 = new Camera(videoElement, {
           onFrame: async () => {
               await holistic.send({ image: videoElement });
           },
           width: 200,
           height: 190
       });
       camera1.start();

	</script>
</body>

</html>